package cn.com.generaldata.os.service.indicator_evaluation.industry_spread_effect;

import java.util.List;

import org.apache.commons.lang3.Validate;
import org.nutz.dao.Cnd;
import org.nutz.dao.Dao;
import org.nutz.dao.sql.Criteria;
import org.nutz.lang.random.R;

import cn.com.generaldata.jsme_indicator_system.entity.Dustry;
import cn.com.generaldata.jsme_indicator_system.entity.IndicatorConsumptResult;
import cn.com.generaldata.jsme_indicator_system.entity.IndicatorEvaluation;
import cn.com.generaldata.os.service.impl.DustryService;
import cn.com.generaldata.os.service.impl.IndicatorConsumptService;
import cn.com.generaldata.os.service.impl.IndicatorProductionService;
import cn.com.generaldata.os.service.indicator_constant.ProvinceIndicatorConstant;
import cn.com.generaldata.os.service.indicator_evaluation.CalculateService;
import cn.com.generaldata.os.service.indicator_evaluation.CalculateServiceHelper;
import cn.com.generaldata.os.util.SpringContextHolder;
import cn.com.generaldata.os.vo.IndicatorAccountVO;

/**
 * 生产最终依赖度指标计算类.
 */
public class ProductionFinalDependenceCalculateService implements CalculateService {

	private Dao dao;

	private Dao indicatorSystemDao;

	private CalculateServiceHelper helper;

	private String defaultTypeName = "生产最终依赖系数";

	@Override
	public void calculateIndicator(IndicatorEvaluation indicator, IndicatorAccountVO indicatorAccountVO) {
		DustryService dustryService = SpringContextHolder.getBean(DustryService.class);
		IndicatorConsumptService indicatorConsumptService = SpringContextHolder.getBean(IndicatorConsumptService.class);
		IndicatorProductionService indicatorProductionService = SpringContextHolder
				.getBean(IndicatorProductionService.class);

		Validate.isTrue(indicatorProductionService.checkHasData(indicatorAccountVO.getYear()), "不存在该年份基本流量表数据");
		Validate.isTrue(indicatorConsumptService.checkHasData(indicatorAccountVO.getYear()), "不存在该年份的直接消耗系数表数据");

		double[][] inverseMatrix = indicatorConsumptService.getConsumptInverseMatrix(indicatorAccountVO.getYear());
		double[][] productionMatrix = indicatorProductionService.getProductionMatrix(indicatorAccountVO.getYear());

		List<Dustry> dustries = dustryService.getEnableDustrys(indicatorAccountVO.getYear());

		for (Dustry dustry : dustries) {
			int dustryIndex = dustryService.getDustryIndex(dustry);
			double[] inverseMatrixRow = inverseMatrix[dustryIndex];
			for (int columnIndex = 0; columnIndex < ProvinceIndicatorConstant.COEFFICIENT_PRODUCT_SUB_TYPE.size(); columnIndex++) {
				double z = getZ(inverseMatrixRow, productionMatrix, columnIndex);
				double zSum = getZSum(inverseMatrixRow, productionMatrix);
				String coefficientName = ProvinceIndicatorConstant.COEFFICIENT_PRODUCT_SUB_TYPE.get(columnIndex);
				String coefficientNameSuffix = ProvinceIndicatorConstant.COEFFICIENT_PRODUCT_SUB_TYPE_SUFFIX
						.get(columnIndex);
				double result = z / zSum;
				saveResult(indicatorAccountVO.getYear(), dustry, coefficientName, coefficientNameSuffix, result);
			}
		}
	}

	private double getZSum(double[] inverseMatrixRow, double[][] productionMatrix) {
		double sum = 0d;
		for (int columnIndex = 0; columnIndex < ProvinceIndicatorConstant.COEFFICIENT_PRODUCT_SUB_TYPE.size(); columnIndex++) {
			sum += getZ(inverseMatrixRow, productionMatrix, columnIndex);
		}
		return sum;
	}

	/**
	 * 
	 * @param inverseMatrixRow
	 * @param productionMatrix
	 * @param columnIndex
	 * @return
	 */
	private double getZ(double[] inverseMatrixRow, double[][] productionMatrix, int columnIndex) {
		double sum = 0d;
		for (int i = 0; i < inverseMatrixRow.length; i++) {
			sum += inverseMatrixRow[i] * productionMatrix[i][columnIndex];
		}
		return sum;
	}

	/**
	 * 保存指标结果.
	 * 
	 * @param indicatorAccountVO
	 * @param result
	 */
	private void saveResult(int year, Dustry dustry, String coefficientName, String coefficientNameSuffix, Double result) {
		Criteria cri = getIndicatorDataCri(year, coefficientName, defaultTypeName + coefficientNameSuffix, dustry);
		IndicatorConsumptResult record = dao.fetch(IndicatorConsumptResult.class, cri);
		if (record != null) {
			dao.clear(IndicatorConsumptResult.class, cri);
		}

		IndicatorConsumptResult icr = new IndicatorConsumptResult();
		icr.setId(R.UU64());
		icr.setYear(year);
		icr.setTypeName(coefficientName);
		icr.setSubTypeName(defaultTypeName + coefficientNameSuffix);
		icr.setDustryId(dustry.getId());
		icr.setIndicatorValue(Double.valueOf(String.format("%.10f", result)));

		dao.insert(icr);
	}

	private Criteria getIndicatorDataCri(int year, String typeName, String subTypeName, Dustry dustry) {
		Criteria cri = Cnd.cri();
		cri.where().and("year", "=", year);
		cri.where().and("typeName", "=", typeName);
		cri.where().and("subTypeName", "=", subTypeName);
		cri.where().and("dustryId", "=", dustry.getId());
		return cri;
	}

	@Override
	public void setDao(Dao dao) {
		this.dao = dao;
	}

	@Override
	public void setIndicatorSystemDao(Dao indicatorSystemDao) {
		this.indicatorSystemDao = indicatorSystemDao;
	}

	@Override
	public void setCalculateServiceHelper(CalculateServiceHelper calculateServiceHelper) {
		helper = calculateServiceHelper;
	}

}
